/*
 * User: user
 * Date: 12/12/2007
 * Time: 14:06:12
 */
package org.conann.util;

import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Maps;
import static com.google.common.collect.Sets.newHashSet;
import org.conann.metadata.AnnotationType;

import javax.webbeans.binding.NonBinding;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import static java.util.Collections.emptyMap;
import static java.util.Collections.unmodifiableMap;
import java.util.Map;
import java.util.Set;

public abstract class AnnotationUtil {

    public static Set<Annotation> getRelevantAnnotations(AnnotatedElement annotatedElement) {
        Annotation[] annotations = annotatedElement.getAnnotations();
        return getRelevantAnnotations(annotations);
    }

    public static Set<Annotation> getRelevantAnnotations(Annotation[] annotations) {
        Set<Annotation> result = newHashSet();
        for (Annotation annotation : annotations) {
            if (AnnotationType.getAnnotationType(annotation) != null) {
                result.add(annotation);
            }
        }
        return result;
    }

    public static Set<Method> getParameterMethods(Class<? extends Annotation> annotationType) {
        Set<Method> parameters = newHashSet();
        for (Method method : annotationType.getDeclaredMethods()) {
            if (!method.isAnnotationPresent(NonBinding.class)) {
                parameters.add(method);
            }
        }
        return parameters;
    }

    public static Map<String, Object> getParameters(Annotation annotation) {
        Set<Method> methods = getParameterMethods(annotation.annotationType());
        if (methods == null) {
            return emptyMap();
        }
        Map<String, Object> parameters = Maps.newHashMap();
        for (Method method : methods) {
            Object value = ReflectionUtil.invokeMethod(method, annotation);
            parameters.put(method.getName(), value);
        }
        return unmodifiableMap(parameters);
    }

    public static boolean isAnnotationExistInHierarchy(final Class<?> type, Class<? extends Annotation> annotation) {
        checkNotNull(type);
        checkNotNull(annotation);
        Class<?> checkedType = type;
        while (checkedType != null) {
            if (checkedType.isAnnotationPresent(annotation)) {
                return true;
            }
            checkedType = checkedType.getSuperclass();
        }
        return false;
    }
}